import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:webview_flutter/webview_flutter.dart';

// Native <-> JS
// 定义枚举类型 BridgeError
enum JSBridgeError {
  handlerNotExistError,
  dataIsInvalidError,
}

// 定义别名 BridgeData
typedef JSBridgeData = dynamic;

// 定义错误回调函数类型 ErrorCallback
typedef JSBridgeErrorCallback = void Function(JSBridgeError errorMessage);

// 定义回调函数类型 Callback
typedef JSBridgeCallback = void Function(JSBridgeData responseData);

// 定义处理函数类型 Handler
typedef JSBridgeHandler = void Function(
    JSBridgeData data, JSBridgeCallback callback);

typedef JSBridgeMessageExecutor = Future<void> Function(
    String javascriptString);

// 定义Flutter和JavaScript之间消息的key
class MessageKey {
  /// js 处理函数 Key
  static String name = "name";
  // 数据Key
  static String data = "data";
  static String flutterCallbackId = "flutterCallbackId";

  static String jsCallbackId = "jsCallbackId";

  /// 错误Key
  static String error = "error";
}

class JSBridge {
  /// 注入的对象名，需跟bridge.js中使用的需要一样
  static String name = "flutterBridge";

  /// 存储注册的处理函数
  final Map<String, JSBridgeHandler> _handlers = {};

  /// 存储回调函数
  final Map<String, JSBridgeCallback> _callbacks = {};

  /// 存储错误回调函数
  final Map<String, JSBridgeErrorCallback> _errorCallbacks = {};

  /// 唯一的回调函数id
  int _callbackId = 0;

  /// messageExecutor 对象，用于执行JavaScript脚本
  JSBridgeMessageExecutor? messageExecutor;

  /// 注入bridge.js，需要注入bridge.js才能使用相关API
  /// [controller] WebViewController , WebViewWidget 对应的controller
  Future<void> injectBridgeJS(WebViewController controller) async {
    // 加载bridge.js
    var jsString = await rootBundle.loadString('assets/js/bridge.js');
    controller.runJavaScript(jsString);
  }

  // 注册一个处理函数
  void register(String name, JSBridgeHandler handler) {
    _handlers[name] = handler;
  }

  // 移除一个处理函数
  void remove(String name) {
    _handlers.remove(name);
  }

  // 调用 JavaScript 处理函数
  Future<void> call(String name, JSBridgeData data,
      {JSBridgeCallback? callback, JSBridgeErrorCallback? errorCallback}) {
    final id = _callbackId.toString();

    _callbackId++;

    if (callback != null) {
      _callbacks[id] = callback;
    }

    if (errorCallback != null) {
      _errorCallbacks[id] = errorCallback;
    }

    return Future(() {
      // 发送消息到 JavaScript
      _postMessage(
          name: name,
          data: data,
          callbackId: id,
          jsCallbackId: null,
          error: null);
    });
  }

  // 发送消息给JS
  void _postMessage(
      {required String name,
      required JSBridgeData data,
      String? callbackId,
      String? jsCallbackId,
      String? error}) {
    var message = {};
    message[MessageKey.name] = name;
    message[MessageKey.data] = data;
    message[MessageKey.flutterCallbackId] = callbackId;
    message[MessageKey.jsCallbackId] = jsCallbackId;
    message[MessageKey.error] = error;

    String jsonString = json.encode(message);
    // 执行JavaScript
    messageExecutor?.call('window.bridge.receiveMessage($jsonString)');
  }

  /// 接收消息
  void receiverMessage(String message) {
    try {
      // 解析成Map
      Map<String, dynamic> body = json.decode(message);

      var data = body[MessageKey.data];

      var flutterCallbackId = body[MessageKey.flutterCallbackId];

      if (flutterCallbackId != null && flutterCallbackId is String) {
        var error = body[MessageKey.error];

        if (error != null && error is String) {
          var errorCallBack = _errorCallbacks[flutterCallbackId];

          errorCallBack?.call(JSBridgeError.handlerNotExistError);
        } else {
          var callback = _callbacks[flutterCallbackId];

          callback?.call(data);
        }
      } else {
        var name = body[MessageKey.name];
        var jsCallbackId = body[MessageKey.jsCallbackId];

        if (name != null &&
            name is String &&
            jsCallbackId != null &&
            jsCallbackId is String) {
          var handler = _handlers[name];

          if (handler != null) {
            handler.call(data, (responseData) {
              _postMessage(
                  name: name, data: responseData, jsCallbackId: jsCallbackId);
            });
          } else {
            _postMessage(
                name: name,
                data: null,
                jsCallbackId: jsCallbackId,
                error: "handlerNotExistError");
          }
        }
      }
    } catch (e) {
      print("解析错误：$e");
    }
  }
}
